/*-------------------------------------------------------------------------
 *
 * utility.h
 *	  utility.c 的原型.
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/tcop/utility.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef UTILITY_H
#define UTILITY_H

#include "tcop/cmdtag.h"
#include "tcop/tcopprot.h"

typedef enum
{
	PROCESS_UTILITY_TOPLEVEL,	/* 顶层交互命令 */
	PROCESS_UTILITY_QUERY,		/* 完整查询，但不是顶层 */
	PROCESS_UTILITY_QUERY_NONATOMIC,	/* 完整查询，非原子
										 * 执行上下文 */
	PROCESS_UTILITY_SUBCOMMAND	/* 查询的一部分 */
} ProcessUtilityContext;

/* 从 ALTER TABLE 递归时所需的信息 */
typedef struct AlterTableUtilityContext
{
	PlannedStmt *pstmt;			/* 外部 ALTER TABLE 命令的 PlannedStmt */
	const char *queryString;	/* 其查询字符串 */
	Oid			relid;			/* ALTER 的目标表的 OID */
	ParamListInfo params;		/* 任何可用于 ALTER TABLE 的参数 */
	QueryEnvironment *queryEnv; /* ALTER TABLE 的执行环境 */
} AlterTableUtilityContext;

/*
 * 这些常量用于描述特定命令的只读程度。
 *
 * COMMAND_OK_IN_READ_ONLY_TXN 意味着即使在 XactReadOnly 设置时，命令也是允许的。
 * 对于不会以影响 pg_dump 输出的方式改变数据库（数据或模式）状态的命令，此位应设置。
 *
 * COMMAND_OK_IN_PARALLEL_MODE 意味着即使在并行模式下，命令也是允许的。
 * 写入元组是被禁止的，任何可能混淆协作进程的操作也是禁止的。
 *
 * COMMAND_OK_IN_RECOVERY 意味着即使在恢复状态下，命令也是允许的。
 * 它不能写 WAL，也不能做会危害从主库接收的未来 WAL 重放的事情。
 */
#define COMMAND_OK_IN_READ_ONLY_TXN	0x0001
#define COMMAND_OK_IN_PARALLEL_MODE	0x0002
#define	COMMAND_OK_IN_RECOVERY		0x0004

/*
 * 如果一个命令对所有目的都是足够只读的，我们称之为严格只读。
 * 为了清晰起见，我们也有一个常量用于完全不只读的命令。
 */
#define COMMAND_IS_STRICTLY_READ_ONLY \
	(COMMAND_OK_IN_READ_ONLY_TXN | COMMAND_OK_IN_RECOVERY | \
	 COMMAND_OK_IN_PARALLEL_MODE)
#define COMMAND_IS_NOT_READ_ONLY	0

/* 插件在ProcessUtility()中获取控制的挂钩 */
typedef void (*ProcessUtility_hook_type) (PlannedStmt *pstmt,
										  const char *queryString,
										  bool readOnlyTree,
										  ProcessUtilityContext context,
										  ParamListInfo params,
										  QueryEnvironment *queryEnv,
										  DestReceiver *dest, QueryCompletion *qc);
extern PGDLLIMPORT ProcessUtility_hook_type ProcessUtility_hook;

extern void ProcessUtility(PlannedStmt *pstmt, const char *queryString,
						   bool readOnlyTree,
						   ProcessUtilityContext context, ParamListInfo params,
						   QueryEnvironment *queryEnv,
						   DestReceiver *dest, QueryCompletion *qc);
extern void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
									bool readOnlyTree,
									ProcessUtilityContext context, ParamListInfo params,
									QueryEnvironment *queryEnv,
									DestReceiver *dest, QueryCompletion *qc);

extern void ProcessUtilityForAlterTable(Node *stmt,
										AlterTableUtilityContext *context);

extern bool UtilityReturnsTuples(Node *parsetree);

extern TupleDesc UtilityTupleDescriptor(Node *parsetree);

extern Query *UtilityContainsQuery(Node *parsetree);

extern CommandTag CreateCommandTag(Node *parsetree);

static inline const char *
CreateCommandName(Node *parsetree)
{
	return GetCommandTagName(CreateCommandTag(parsetree));
}

extern LogStmtLevel GetCommandLogLevel(Node *parsetree);

extern bool CommandIsReadOnly(PlannedStmt *pstmt);

#endif							/* UTILITY_H */
